package com.example.demo2_review.thread_pool;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.*;

/**
 * @Author zwp14
 * @create 2024/6/18 22:52
 * @description 线程池
 */
@Slf4j
public class ThreadPoolExample {

    private static ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    private static final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(1000);


    public static void main(String[] args) {
        //创建线程工厂
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        //创建阻塞队列
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100);
        //创建拒绝策略
        RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.CallerRunsPolicy();
        //使用ThreadPoolExecutor创建线程池
//        ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor(threadFactory, workQueue, rejectedExecutionHandler);

        //使用ThreadPoolTaskExecutor创建线程池
//        extracted(rejectedExecutionHandler);

        //使用线程池按照顺序输出1-100
//        orderPrintln();
        orderPrintln2();
        //信号量数组
//        threadPrintln();

    }

    private static void orderPrintln2() {
/*使用单线程执行器：
创建一个单线程的 ExecutorService，保证任务按提交顺序执行。
ExecutorService executorService = Executors.newSingleThreadExecutor();

        for (int i = 0; i < 1000; i++) {
            int finalI = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("Thread is running -- {}", finalI);
                }
            });
        }

        executorService.shutdown();*/


/*  CountDownLatch 可以在多线程情况下确保特定任务的执行顺序。
ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(10);
        CountDownLatch previous = new CountDownLatch(0);// 初始无需等待, CountDownLatch 是一种同步工具，它允许一个或多个线程等待一组操作完成。

        for (int i = 0; i < 1000; i++) {
            final int finalI = i;
            CountDownLatch finalPrevious = previous;
            CountDownLatch current = new CountDownLatch(1);
            threadPoolExecutor.execute(() -> {
                try {
                    finalPrevious.await(); // 等待前一个任务完成
                    log.info("Thread is running -- " + finalI);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    current.countDown(); // 标记当前任务完成
                }
            });
            previous = current;
        }
        threadPoolExecutor.shutdown();*/



        /*Future依赖链：使用Future的方式串行化任务。*/
        ExecutorService executor = Executors.newFixedThreadPool(10);
        CompletableFuture<Void> future = CompletableFuture.completedFuture(null);
        for (int i = 0; i < 1000; i++) {
            final int finalI = i;
            future = future.thenRunAsync(() -> {
                log.info("Thread is running -- " + finalI);
            }, executor);
        }
        future.join();
        executor.shutdown();
    }


    private static void threadPrintln() {
        Semaphore[] semaphores = new Semaphore[100];
        for (int i = 0; i < semaphores.length; i++) {
            semaphores[i] = new Semaphore(i==0?1:0);
        }

        for (int i = 0; i < 100; i++) {
            int finalI = i;
            new Thread(() -> {
                boolean isAcquire = false;
                try {
                    semaphores[finalI].acquire();;
                    isAcquire = true;
                    System.out.println(Thread.currentThread().getName()+":--"+ finalI);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    if (isAcquire&&finalI + 1 < 100){
                        semaphores[finalI+1].release();
                    }
                }

            }, "t" + i).start();
        }

    }

    /**
     * 使用线程池按照顺序输出1-100
     */
    private static void orderPrintln() {
        Semaphore[] semaphores = new Semaphore[1001];

        // 初始化信号量
        for (int i = 0; i < semaphores.length; i++) {
            semaphores[i] = new Semaphore(0);
        }
        // 第一个信号量初始化为1，表示可以开始
        semaphores[0].release();

        ThreadFactory threadFactory = new ThreadFactory() {

            private int counter = 0;

            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "CustomThread-" + counter++);
            }
        };

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), threadFactory);

        // 初始化队列
        for (int i = 0; i < 1000; i++) {
            queue.add(i);
        }

        for (int i = 0; i < 1000; i++) {
            final int finalI = i;
            threadPoolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphores[finalI].acquire();// 等待前一个任务完成
                        int number = queue.take();
                        log.info("Thread is running -- {}", number);
                        semaphores[finalI + 1].release();// 释放下一个任务
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            });
        }

        threadPoolExecutor.shutdown();
    }


    /**
     * 使用ThreadPoolTaskExecutor创建线程池
     *
     * @param rejectedExecutionHandler 拒绝策略
     */
    private static void extracted(RejectedExecutionHandler rejectedExecutionHandler) {
        //创建线程池2
        /*
         * ThreadPoolTaskExecutor是Spring Framework提供的一个线程池实现类
         * 它是ThreadPoolExecutor的一个具体实现，提供了更多的配置选项和Spring特定的功能
         * 可以通过XML配置或者Java代码进行配置，支持Spring的依赖注入和生命周期管理。
         * 如果需要将线程池配置整合到Spring的IoC容器中，或者需要利用Spring提供的额外功能，
         * 推荐使用ThreadPoolTaskExecutor。
         * */

        executor.setThreadNamePrefix("zwp-creat-test-thread-");//线程名称前缀
        executor.setCorePoolSize(2);//核心线程数
        executor.setMaxPoolSize(5);//最大线程数
        executor.setQueueCapacity(100);//阻塞队列个数
        executor.setKeepAliveSeconds(10);// 设置空闲线程的存活时间，单位为秒
        executor.setRejectedExecutionHandler(rejectedExecutionHandler);//拒绝策略
        /*
         * ThreadPoolTaskExecutor 是一个复杂的线程池管理器，
         * 它包含了多个配置参数（如核心线程数、最大线程数、任务队列、空闲线程存活时间等），
         * 以及一些默认的行为（如拒绝策略）。
         * 在调用 initialize() 方法之前，设置线程池的各种参数是不生效的，
         * 因为这些参数只是配置信息，需要通过 initialize() 方法来实际初始化线程池的内部结构和工作机制。
         * */
        executor.initialize();

        for (int i = 0; i < 1000; i++) {
            /*
             * 没有返回值 (void)，它适合用于执行不需要返回结果的任务。
             * 适合用于 fire-and-forget 的场景，即提交任务后不关心其执行结果，只关注任务是否被成功执行。
             * */
            executor.execute(ThreadPoolExample::test);
            /*
             * 返回一个 Future 对象，可以用来获取任务执行的结果或者进行异常处理。
             * 更适合需要获取任务执行结果的场景，可以通过 Future 对象获取任务的执行状态和结果，
             * 也可以通过 Future 对象进行任务取消操作等。
             * */
            Future<?> future = executor.submit(ThreadPoolExample::test);
            try {
                Object o = future.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        test();
        executor.shutdown();
    }

    /**
     * 使用ThreadPoolExecutor创建线程池
     *
     * @param threadFactory            县城工厂
     * @param workQueue                阻塞队列
     * @param rejectedExecutionHandler 拒绝策略
     * @return 线程池
     */
    private static ThreadPoolExecutor getThreadPoolExecutor(ThreadFactory threadFactory, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler rejectedExecutionHandler) {

        //创建线程池1
        /*
         * ThreadPoolExecutor是Java标准库提供的线程池实现类。
         * 通常通过直接实例化对象并设置参数来配置，支持更为灵活的配置方式。
         * 可以设置核心线程数、最大线程数、任务队列、线程工厂、拒绝策略等。
         * 如果你只是需要一个简单的线程池，并且不需要Spring提供的特定功能，
         * 可以直接使用ThreadPoolExecutor。*/
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                2,//核心线程数
                5,//最大线程数
                10,//存活时间
                TimeUnit.SECONDS,//时间单位
                workQueue,//阻塞队列
                threadFactory,//线程工厂
                rejectedExecutionHandler//拒绝策略：由调用者去执行
        );
        Semaphore[] semaphores = new Semaphore[1000];
        for (int i = 0; i < semaphores.length; i++) {
            semaphores[i] = new Semaphore(i==0?1:0);
        }
        for (int i = 0; i < 1000; i++) {
            int finalI = i;
            threadPoolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    boolean isAcquire = false;
                    try {
                        semaphores[finalI].acquire();
                        isAcquire = true;
                        log.info("Thread is running -- {}", finalI);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        if (isAcquire&&finalI+1<1000) {
                            semaphores[finalI+1].release();
                        }
                    }
                }
            });
        }
        threadPoolExecutor.shutdown();
        return threadPoolExecutor;
    }

    private static void test() {
        log.info("Thread is running");
    }

}
